/*******************************************************************************
 * @file Copyright 2009 The CREATE Lab at CMU
 * 
 *       This file is part of JubJub, an open source project.
 *       http://code.google.com/p/jubjub/
 * 
 *       Redistribution and use in source and binary forms, with or without
 *       modification, are permitted provided that the following conditions are
 *       met:
 * 
 *       Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 * 
 *       Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 * 
 *       Neither the name of Carnegie Mellon nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 * 
 *       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *       "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *       HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *       SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *       LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *       OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

package edu.cmu.ri.createlab.jj.ui;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import edu.cmu.ri.createlab.jj.blocks.BlockBlock;
import edu.cmu.ri.createlab.jj.blocks.FlowBlock;
import edu.cmu.ri.createlab.jj.blocks.RefBlock;
import edu.cmu.ri.createlab.jj.blocks.BlockDefs.BlockTypes;
import edu.cmu.ri.createlab.jj.blocks.BlockDefs.FlowTypes;
import edu.cmu.ri.createlab.jj.projects.JJProject;
import edu.cmu.ri.createlab.jj.projects.JJSubTab;
import edu.cmu.ri.createlab.jj.projects.JJTab;
import edu.cmu.ri.createlab.jj.shapes.RefShape;
import static edu.cmu.ri.createlab.jj.shapes.ShapeDefs.*;
import edu.cmu.ri.createlab.jj.visitors.BVDrawer;
import edu.cmu.ri.createlab.jj.visitors.BlockVisitorInterface;

public class PalettePanel extends JPanel implements JJPanelInterface, MouseListener, MouseMotionListener
{
   String name;
   JJTab tab;
   double scale;
   int startX;
   int startY;
   BVDrawer drawer;
   private LinkedList<RefBlock> dragBlocks;
   ArrayList<ArrayList<RefShape>> shapes;
   protected javax.swing.event.EventListenerList listenerList =
      new javax.swing.event.EventListenerList();
   
   public void addJJDragReadyListener(JJDragReadyListener listener)
   {
      listenerList.add(JJDragReadyListener.class, listener);
   }
   
   // This methods allows classes to unregister for MyEvents
   public void removeJJDragReadyListener(JJDragReadyListener listener) 
   {
       listenerList.remove(JJDragReadyListener.class, listener);
   }

// This private class is used to fire MyEvents
   void fireJJDragReadyEvent(JJDragReadyEvent evt) 
   {
       Object[] listeners = listenerList.getListenerList();
       // Each listener occupies two elements - the first is the listener class
       // and the second is the listener instance
       for (int i=0; i<listeners.length; i+=2) {
           if (listeners[i]==JJDragReadyListener.class) {
               ((JJDragReadyListener)listeners[i+1]).jjDragReadyOccurred(evt);
           }
       }
   }
   
   
   
   public PalettePanel(String s, BVDrawer drawer)
   {
      name = s;
      shapes = new ArrayList<ArrayList<RefShape>>();
      dragBlocks = new LinkedList<RefBlock>();
      scale = 0.75;
      startX = 10;
      startY = 10;
      this.drawer = drawer;
      this.setLayout(null);
      
      this.addMouseListener(this);
   }
   

   public LinkedList<RefBlock> getDragBlocks()
   {
      return dragBlocks;
   }
   
   public void setScale(double scale)
   {
      this.scale = scale;
   }
   
   public void setTab(JJTab tab)
   {
      this.tab = tab;
      Iterator<JJSubTab> sIt = tab.getSubTabs().iterator();
      int tempX = (int) (startX + ioNameXOffset*scale);
      int tempY = (int) (startY);
      int maxX = 300;
      while(sIt.hasNext())
      {
         JJSubTab subTab = sIt.next();
         ArrayList<RefShape> stList = new ArrayList<RefShape>();
         shapes.add(stList);
         Iterator<RefBlock> rIt = subTab.getBlocks().iterator();
         tempY += 0.5*paletteSpacing*scale;
         while(rIt.hasNext())
         {
            RefShape tempRS = new RefShape(tempX, tempY, rIt.next(), scale, this);
            stList.add(tempRS);
            tempY = (int) (tempRS.getBounds()[3]);
            if(tempRS.getBounds()[2] > maxX) maxX = tempRS.getBounds()[2];
            if(!(tempRS.getRef().getBlock() != null 
                  && tempRS.getRef().getBlock().getType() == BlockTypes.FLOW
                  && tempRS.getRef().getIndex() < 3)) tempY += (int)(paletteSpacing*scale);
         }
         //tempY += (int)(paletteSpacing*scale);
      }
      this.setPreferredSize(new Dimension(maxX, tempY));
      this.revalidate();
   }
   
   public void update()
   {
      if(tab != null) setTab(tab);
   }
   
   public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      if(tab != null) 
      {
         g.setFont(drawer.getFont());
//         tab.draw(g, this, drawer);
         Iterator<JJSubTab> stIt = tab.getSubTabs().iterator();
         int index = 0;
         int tempX = startX;
         int tempY = startY;
         while(stIt.hasNext())
         {
            Iterator<RefShape> rIt = shapes.get(index).iterator();
            drawer.setGraphics(g);
            drawer.setObserver(this);
            drawer.setScale(scale);
            g.drawString(stIt.next().getName(), tempX, tempY);
            tempY += paletteSpacing*scale;
            while(rIt.hasNext())
            {
               RefShape tempRef = rIt.next();
               tempRef.draw(g, this, drawer);
               tempY = (int) (tempRef.getBounds()[3] + paletteSpacing*scale);
            }
            
            index++;
         }
      }
   }
   
   public static void main(String[] args)
   {
      BVDrawer drawer = new BVDrawer();
      PalettePanel wp = new PalettePanel("pp",drawer);
      wp.setTab(JJProject.getTestProject().getTabs().get(0));
      JScrollPane sp = new JScrollPane();
      Dimension d1 = new Dimension(300,600);
      sp.setPreferredSize(d1);
      sp.setViewportView(wp);
      
      JFrame frame = new JFrame("BVDrawer test");
      
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(sp);
      
      frame.pack();
      
      frame.setVisible(true);
   }


   
   public BlockVisitorInterface[] getVisitors()
   {
      // TODO Auto-generated method stub
      return null;
   }

   
   public void mouseClicked(MouseEvent e)
   {
      // TODO Auto-generated method stub
      
   }

   
   public void mouseEntered(MouseEvent e)
   {
      // TODO Auto-generated method stub
      
   }

   
   public void mouseExited(MouseEvent e)
   {
      // TODO Auto-generated method stub
      
   }

   
   public void mousePressed(MouseEvent e)
   {
      dragBlocks.clear();
      Iterator<ArrayList<RefShape>> lists = shapes.iterator();
      while(lists.hasNext())
      {
         ArrayList<RefShape> aList = lists.next();
         Iterator<RefShape> sList = aList.iterator();
         int index = 0;
         while(sList.hasNext())
         {
            try
            {
               RefShape tempShape = sList.next();
               if(tempShape.contains(e.getX(), e.getY()))
               {
                  ///For while loops make sure to get both refs
                  if(tempShape.getRef().getBlock() != null
                        && tempShape.getRef().getBlock().getType() == BlockTypes.FLOW
                        && tempShape.getRef().getIndex() == 3) 
                  {
                        if(((FlowBlock)tempShape.getRef().getBlock()).getFType() == FlowTypes.IFELSE)
                           this.dragBlocks.add(aList.get(index-2).getRef().clone(1));
                        this.dragBlocks.add(aList.get(index-1).getRef().clone(1));
                  }
                  if(tempShape.getRef().getBlock() != null
                        && tempShape.getRef().getBlock().getType() == BlockTypes.FLOW
                        && tempShape.getRef().getIndex() == 2) 
                  {
                        if(((FlowBlock)tempShape.getRef().getBlock()).getFType() == FlowTypes.IFELSE)
                           this.dragBlocks.add(aList.get(index-1).getRef().clone(1));
                  }
                  this.dragBlocks.add(tempShape.getRef().clone(1));
                  if(tempShape.getRef().getBlock() != null
                        && tempShape.getRef().getBlock().getType() == BlockTypes.FLOW
                        && tempShape.getRef().getIndex() == 2) 
                  {
                        if(((FlowBlock)tempShape.getRef().getBlock()).getFType() == FlowTypes.IFELSE)
                           this.dragBlocks.add(aList.get(index+1).getRef().clone(1));
                  }
                  if(tempShape.getRef().getBlock() != null
                        && tempShape.getRef().getBlock().getType() == BlockTypes.FLOW
                        && tempShape.getRef().getIndex() == 0)
                  {
                     this.dragBlocks.add(aList.get(index+1).getRef().clone(1));
                     if(((FlowBlock)tempShape.getRef().getBlock()).getFType() == FlowTypes.IFELSE)
                        this.dragBlocks.add(aList.get(index+2).getRef().clone(1));
                  }
                  break;
               }
               index++;
            } catch (Exception e1)
            {
               // TODO Auto-generated catch block
               System.err.println(e1.getMessage());
            }
         }
      }
      if(!dragBlocks.isEmpty()) fireJJDragReadyEvent(new JJDragReadyEvent(this));
   }

   
   public void mouseReleased(MouseEvent e)
   {
      // TODO Auto-generated method stub
      
   }

   
   public void mouseDragged(MouseEvent e)
   {
      // TODO Auto-generated method stub
      
   }

   
   public void mouseMoved(MouseEvent e)
   {
      // TODO Auto-generated method stub
      
   }
   
}
